package com.ylr.gateway.framework.filter;

import com.ylr.base.common.constant.Constant;
import com.ylr.base.common.enums.ResultEnum;
import com.ylr.base.common.interfaces.BaseResultEnum;
import com.ylr.base.common.tool.Result;
import com.alibaba.fastjson2.JSON;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-04-30 21:14:57
 * className: HeadGlobFilter 请求头参数校验过滤器
 * version: 1.0
 * description:
 */
@Component
public class HeadGlobFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(HeadGlobFilter.class);

    @Value("${head-filter.enabled}")
    private Boolean enabled;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (Boolean.FALSE.equals(enabled)) {
            log.debug("不开启请求头校验");
            return chain.filter(requestHeaderBuild(exchange, StringUtils.EMPTY, StringUtils.EMPTY, StringUtils.EMPTY));
        }

        ServerHttpRequest request = exchange.getRequest();
        // 获取请求头对象
        HttpHeaders headers = request.getHeaders();
        // 请求指纹
        String fingerprint = headers.getFirst(Constant.FINGERPRINT);
        if (StringUtils.isEmpty(fingerprint)) {
            log.warn("请求头 => 请求指纹为空");
            return writeResponse(exchange, ResultEnum.REQUEST_FAIL);
        }
        // 请求设备
        String device = headers.getFirst(Constant.DEVICE);
        String os = headers.getFirst(Constant.OS);
        String userAgent = headers.getFirst("User-Agent");
        if (StringUtils.isEmpty(device)) {
            // TODO 等待完善
            device = "asd";
            if (StringUtils.isEmpty(device)) {
                log.warn("请求头 => 获取请求设备失败");
                return writeResponse(exchange, ResultEnum.REQUEST_FAIL);
            }
        }
        if (StringUtils.isEmpty(os)) {
            // TODO 等待完善
            os = "asd";
            if (StringUtils.isEmpty(os)) {
                log.warn("请求头 => 获取请求设备操作系统失败");
                return writeResponse(exchange, ResultEnum.REQUEST_FAIL);
            }
        }

        return chain.filter(requestHeaderBuild(exchange, fingerprint, device, os));
    }

    @Override
    public int getOrder() {
        // 数值越小，优先级越高
        return -2;
    }

    /**
     * 封装返回数据
     * @param exchange 服务交换机对象
     * @return 返回结果
     */
    private Mono<Void> writeResponse(ServerWebExchange exchange, BaseResultEnum baseResultEnum) {
        ServerHttpResponse serverHttpResponse = exchange.getResponse();
        serverHttpResponse.setStatusCode(HttpStatus.OK);
        serverHttpResponse.getHeaders().setContentType(MediaType.valueOf("application/json;charset=UTF-8"));
        Result<Object> result = Result.getResult(baseResultEnum);
        DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(JSON.toJSONBytes(result));
        return serverHttpResponse.writeWith(Mono.just(buffer));
    }

    /**
     * 请求头增加新的内容
     * @param exchange 请求交换机
     * @return 变更后的请求交换机对象
     */
    private ServerWebExchange requestHeaderBuild(ServerWebExchange exchange, String fingerprint, String device, String system) {
        ServerHttpRequest request = exchange.getRequest()
                .mutate()
                .header(Constant.FINGERPRINT, fingerprint)
                .header(Constant.DEVICE, device)
                .header(Constant.OS, system)
                .build();
        return exchange.mutate().request(request).build();
    }

}
